// Copyright (c) 2007, Commerce360, Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions 
// are met:
//
//     * Redistributions of source code must retain the above copyright 
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright 
//       notice, this list of conditions and the following disclaimer in 
//       the documentation and/or other materials provided with the 
//       distribution.
//     * Neither the name of the Commerce360, Inc. nor the names of its 
//       contributors may be used to endorse or promote products derived 
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

package com.directthought.elasticweb.nettica;

import java.util.ArrayList;
import java.util.List;

import org.apache.axis.encoding.Base64;
import com.directthought.elasticweb.nettica.dnsapi.*;

public class NetticaAPI {
    private String username;
    private String password;

    public NetticaAPI(String username, String password) {
	this.username = username;
	this.password = Base64.encode(password.getBytes());
    }

    public void addARecord(String domainName, String hostname, String ipv4, int ttl) throws NetticaException {
	try {
	    DnsApiAsmxSoap client = new DnsApiAsmxLocator().getDnsApiAsmxSoap();
	    DomainRecord d = new DomainRecord();
	    DnsResult result = null;
	    d.setRecordType("A");
	    d.setDomainName(domainName);
	    d.setHostName(hostname);
	    d.setData(ipv4);
	    d.setTTL(ttl);
	    result = client.addRecord(username, password, d);
	    if (result.getStatus() < 200) {
		throw new NetticaException(decodeStatus(result.getStatus()));
	    }
	} catch (javax.xml.rpc.ServiceException ex) {
	    throw new NetticaException("RPC Service exception: " + ex.getMessage(), ex);
	} catch (java.rmi.RemoteException ex) {
	    throw new NetticaException("RMI Remote exception: " + ex.getMessage(), ex);
	}
    }

    public void deleteARecord(ARecord record) throws NetticaException {
	deleteARecord(record.domainName, record.hostname, record.data, record.ttl);
    }

    public void deleteARecord(String domainName, String hostname, String ipv4, int ttl) throws NetticaException {
	try {
	    DnsApiAsmxSoap client = new DnsApiAsmxLocator().getDnsApiAsmxSoap();
	    DomainRecord d = new DomainRecord();
	    DnsResult result = null;
	    d.setRecordType("A");
	    d.setDomainName(domainName);
	    d.setHostName(hostname);
	    d.setData(ipv4);
	    d.setTTL(ttl);
	    result = client.deleteRecord(username, password, d);
	    if (result.getStatus() < 200) {
		throw new NetticaException(decodeStatus(result.getStatus()));
	    }
	} catch (javax.xml.rpc.ServiceException ex) {
	    throw new NetticaException("RPC Service exception: " + ex.getMessage(), ex);
	} catch (java.rmi.RemoteException ex) {
	    throw new NetticaException("RMI Remote exception: " + ex.getMessage(), ex);
	}
    }

    public List<ARecord> listARecord(String domainName) throws NetticaException {
	ArrayList<ARecord> ret = new ArrayList<ARecord>();
	try {
	    DnsApiAsmxSoap client = new DnsApiAsmxLocator().getDnsApiAsmxSoap();
	    DomainResult info = null;
	    String host = domainName;
	    info = client.listDomain(username, password, host);
	    if (info.getResult().getStatus() != 200) {
		throw new NetticaException(decodeStatus(info.getResult().getStatus()));
	    } else {
		for (DomainRecord r : info.getRecord()) {
		    ret.add(new ARecord(r.getHostName(), r.getDomainName(), r.getData(), r.getTTL()));
		}
	    }
	    return ret;
	} catch (javax.xml.rpc.ServiceException ex) {
	    throw new NetticaException("RPC Service exception: " + ex.getMessage(), ex);
	} catch (java.rmi.RemoteException ex) {
	    throw new NetticaException("RMI Remote exception: " + ex.getMessage(), ex);
	}
    }

    public ServiceInfo getServiceInfo() throws NetticaException {
	try {
	    DnsApiAsmxSoap client = new DnsApiAsmxLocator().getDnsApiAsmxSoap();
	    ServiceResult info = client.getServiceInfo(username, password);
	    DnsResult result = info.getResult();
	    int status = result.getStatus();
	    if (status != 200) {
		throw new NetticaException(decodeStatus(result.getStatus()));
	    } else {
		return new ServiceInfo(info.getRemainingCredits(),
					info.getTotalCredits(),
					info.getServiceRenewalDate().getTime().toString());
	    }
	} catch (javax.xml.rpc.ServiceException ex) {
	    throw new NetticaException("error: RPC Service exception: " + ex.getMessage(), ex);
	} catch (java.rmi.RemoteException ex) {
	    throw new NetticaException("error: RMI Remote exception: " + ex.getMessage(), ex);
	}
    }

    private String decodeStatus(int status) {
	switch (status) {
	    case 200:
		return "Success";
	    case 401:
		return "Access denied";
	    case 404:
		return "Not found";
	    case 431:
		return "Record already exists";
	    case 432:
		return "Invalid record type. Must be \"A\",\"MX\",\"CNAME\",\"F\",\"TXT\",\"SRV\"";
	    case 450:
		return "No service";
	    case 460:
		return "Your service has expired";
	    default:
		return "Unknown status code";
	}
    }

    public class ARecord {
	String hostname;
	String domainName;
	String data;
	int ttl;

	public ARecord(String hostname, String domainName, String data, int ttl) {
	    this.hostname = hostname;
	    this.domainName = domainName;
	    this.data = data;
	    this.ttl = ttl;
	}
    }

    public class ServiceInfo {
	int remainingCredits;
	int totalCredits;
	String renewalDate;

	public ServiceInfo(int remainingCredits, int totalCredits, String renewalDate) {
	    this.remainingCredits = remainingCredits;
	    this.totalCredits = totalCredits;
	    this.renewalDate = renewalDate;
	}
    }
}

